#pragma once
#include <vector>
#include <string>
#include <map>
//#include <boost/shared_ptr.hpp>
#include "NetAddress.h"
#include "ViewerException.h"

struct NetNode {
  NetNode(const NetAddress& addr,
          const std::string& name = "") 
    : addr(addr)
    , name(name)
  {}

  const NetAddress& getAddress() const {
    return addr;
  }

  const std::string& getName() const {
    return name;
  }
   
private:
  NetAddress addr;
  std::string name;
};

typedef std::vector<NetNode> NetNodes;

struct SubNet {
  
  typedef std::string Id;

  SubNet(const Id& id,
         const NetAddress& ipNetMask)
  : id(id)
  , ipNetMask(ipNetMask)
  {}

  SubNet(){} //for std::map
   
  const Id& getId() const {
    return id;
  }

  const NetAddress& getIpNetMask() const {
    return ipNetMask;
  }

  const NetNodes& getNodes() const {
    return nodes;
  }

  void addNode(const NetNode& node) {
    nodes.push_back(node);
  }

  static Id strToId(const std::string& str) {
    return str;
  }

private:
  NetNodes nodes;
  Id id;
  NetAddress ipNetMask;
};

typedef std::vector<SubNet> SubNets;
typedef std::map<SubNet::Id, SubNet> SubNetMap;

struct NetInterface {

  NetInterface(const NetAddress& address,               
               const std::string name,
               const SubNet::Id& subNetId,
               size_t inBytes,
               size_t outBytes) 
    : node(address, name)
    , subNetId(subNetId)
    , inBytes(inBytes)
    , outBytes(outBytes)
  {}
 
  const NetAddress& getAddress() const {
    return node.getAddress();
  }

  const IpV4Addr getMask() const {
    return node.getAddress().getIpV4NetMask();
  }

  const SubNet::Id& getSubNetId() const {
    return subNetId;
  }

  const std::string& getName() const {
    return node.getName();
  }

  size_t getInBytes() const {
    return inBytes;
  }

  size_t getOutBytes() const {
    return outBytes;
  }

private:
  NetNode node;
  SubNet::Id subNetId;
  size_t inBytes;
  size_t outBytes;
};

typedef std::vector<NetInterface> NetInterfaces;

struct NetRouter {
  
  NetRouter(const std::string& description)
    : description(description)
  {}

  const std::string& getDescription() const {
    return description;
  }

  const NetInterfaces& getInterfaces() const { 
    return interfaces; 
  }

  void addInterface(const NetInterface& interface) {
    interfaces.push_back(interface);
  }

private:
  NetInterfaces interfaces;
  std::string description;
};

typedef std::vector<NetRouter> NetRouters;

struct Network {
  Network(const std::string& id)
    : id(id)
  {}

  const std::string& getId() const {
    return id;
  }

  void addRouter(const NetRouter& router) {
    netRouters.push_back(router);
  }

  void addSubNet(const SubNet subNet) {
    subNets[subNet.getId()] = subNet;
  }

  const SubNet& getSubNetById(const SubNet::Id& id) const {
    SubNetMap::const_iterator it = subNets.find(id);
    if (it == subNets.end()) {
      throw ViewerException("Couldn't find subnet with provided id");
    } else {
      return it->second;
    }
  }

  const NetRouters& getRouters() const { 
    return netRouters; 
  }

  const SubNetMap& getSubNetworks() const { 
    return subNets; 
  }
private:
  NetRouters netRouters;
  SubNetMap subNets;
  std::string id;
};

typedef std::vector<Network> Networks;

struct NetworkSnapshot { 
  const Networks& getNetworks() const {
    return networks;
  }
  
  void addNetwork(const Network& network) {
    networks.push_back(network);
  }
private:
  Networks networks;
};
//typedef boost::shared_ptr<NetData> NetDataPtr;
//typedef std::auto_ptr<NetData> NetDataPtr;
typedef NetworkSnapshot* NetworkSnapshotPtr;

